package sunyu.tools.mongodb;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoDatabase;
import org.nutz.lang.Lang;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * mongodb数据库操作类
 * <p>
 * http://mongodb.github.io/mongo-java-driver/3.3/driver/getting-started/installation-guide/
 *
 * @author 孙宇
 */
@Component
public class MongoTools {

    public static final String defaultName = "main";
    private static final ConcurrentHashMap<String, MongoClient> mongoClientMap = new ConcurrentHashMap<>();
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @PreDestroy
    public void destroy() {
        logger.info("销毁所有MongoDB客户端开始");
        for (Map.Entry<String, MongoClient> entry : mongoClientMap.entrySet()) {
            entry.getValue().close();
        }
        logger.info("销毁所有MongoDB客户端结束");
    }

    public MongoClient getClient(String clientName) {
        return mongoClientMap.get(clientName);
    }

    public void addClient(String clientName,
                          String servers) {
        logger.info("添加客户端：{}", clientName);
        if (mongoClientMap.containsKey(clientName)) {
            logger.error("{}已存在", clientName);
        } else {
            List<ServerAddress> serverAddressList = new ArrayList<>();
            for (String serverAddress : servers.split(",")) {
                String[] host = serverAddress.split(":");
                serverAddressList.add(new ServerAddress(host[0], Integer.parseInt(host[1])));
            }
            MongoClientOptions.Builder options = MongoClientOptions.builder();
            options.socketKeepAlive(true);// 是否保持长链接
            options.connectTimeout(5000);// 链接超时时间
            options.socketTimeout(5000); // read数据超时时间
            options.readPreference(ReadPreference.primary()); // 最近优先策略
            options.connectionsPerHost(30); // 每个地址最大请求数
            options.maxWaitTime(1000 * 60 * 2); // 长链接的最大等待时间
            options.threadsAllowedToBlockForConnectionMultiplier(50); // 一个socket最大的等待请求数
            MongoClient mongoClient = new MongoClient(serverAddressList, options.build());
            mongoClientMap.put(clientName, mongoClient);
        }
    }

    public MongoDatabase getDatabase(String clientName,
                                     String databaseName) {
        return mongoClientMap.get(clientName).getDatabase(databaseName);
    }

    public <T> T execute(String clientName,
                         String databaseName,
                         DatabaseCallback<T> action) {
        try {
            return action.doInDatabase(getDatabase(clientName, databaseName));
        } catch (Throwable throwable) {
            throw Lang.wrapThrow(throwable);
        }
    }

}
